#pragma once
#include "StdAfx.h"


/*
 * The class that extends std::vector as to allow search by Name and SubName
 * Note that this class can only contain pointers to Base child classes or any other class with an attribute "string Name"
 * Using it with any class non-compliant to the last statement will result in a compilation error
 */
template<class T>
class BBVector : public std::vector<T>, public Base
{
public:
	BBVector(void):Base(BaseDesc()){};
	virtual ~BBVector(void)
	{
		clear();
		this->resize(0);
	};
	//get by name function
	T GetByName(string name)
	{
		return SafeGet(GetIdByName(name));
	};
	//returns the first T whose name matches the supplied name by a substring comparison
	T GetBySubName(string name)
	{
		return SafeGet(GetIdBySubName(name));
	}
	//get id by name
	int GetIdByName(string name)
	{
		return GetIdByName_WithComparator(name, &BBVector::IsName);
	}
	//does that vector have an entry with the given name?
	bool hasName(string name)
	{
		return IsInBounds(GetIdByName(name));
	}
	//same as GetBySubName but returns ID instead
	int GetIdBySubName(string name)
	{
		return GetIdByName_WithComparator(name, &BBVector::IsSubName);
	}
	//remove by name
	T remove(string name)
	{
		return SafeErase(GetIdByName(name));
	}
	//removes by subname
	T subRemove(string name)
	{
		return SafeErase(GetIdBySubName(name));
	}
	//get a random entry from that array
	T getRandom()
	{
		return SafeGet(roll(size())-1);
	}
	//get a random vector of max size n, 
	BBVector<T> GetRandomVector(unsigned int n)
	{
		//create a copy of this vector
		BBVector<T> randVect=*this;
		//if it's bigger than n
		if(size()>n)
		{
			//trim it to n by removing random entries from it
			unsigned int nTrim=randVect.size()-n;
			for(unsigned int i=0;i<nTrim;i++)
				randVect.erase(randVect.begin()+roll(randVect.size())-1);
		}
		return randVect;
	}
private:
	//this is the get function that throws a specialized exception for the log file
	T SafeGet(int id)
	{
		if(!IsInBounds(id))
			throw BException(
			"Vector "<<Name<<": "
			"id out of bounds => "
			"size: "<<string::intToAlpha(size())<<" "
			"id: "<<string::intToAlpha(id));
		else return at(id);
	}
	T SafeErase(int id)
	{
		T t=SafeGet(id);
		erase(begin()+id);
		return t;
	}
	bool IsInBounds(int id)
	{
		if(id>(int)size()
			||id<0)
			return false;
		return true;
	}
	int GetIdByName_WithComparator(string name, bool(BBVector::*comparator)(string, string))
	{
		for(unsigned int i=0;i<size();i++)
			if((this->*comparator)(name, at(i)->Name))
				return i;
		throw BException(
			"Vector "<<Name<<": "
			"name "<<name<<" has not been found.");
	}
	bool IsSubName(string name_1, string name_2)
	{
		return name_1%name_2;
	}
	bool IsName(string name_1, string name_2)
	{
		return name_1^name_2;
	}
};

